package com.king.designpatterns.结构型模式.组合模式;

/**
 * 组合模式（Composite Pattern）也叫合成模式，用来描述部分与整体的关系。
 *
 * 定义：将对象组合成树形结构以表示“部分—整体”的层次结构，使得用户对单个对象和组合对象的使用具有一致性。
 *
 * 角色：
 *      ■ 抽象构件（Component）角色：
 *          该角色定义参加组合对象的共有方法和属性，规范一些默认的行为接口。
 *      ■ 叶子构件（Leaf）角色：
 *          该角色是叶子对象，其下没有其他的分支，定义出参加组合的原始对象的行为。
 *      ■ 树枝构件（Composite）角色：
 *          该角色代表参加组合的、其下有分支的树枝对象，它的作用是将树枝和叶子组合成一个树形结构，并定义出管理子对象的方法，如add()、remove()等。
 *
 * 优缺点：
 *      优点：
 *          ■ 高层模块调用简单。一棵树形机构中的所有节点都是 Component，局部和整体对调用者来说没有任何区别，
 *              即高层模块不必关心自己处理的是单个对象还是整个组合结构，简化了高层模块的代码。
 *          ■ 节点自由增加。使用组合模式后，如果想增加一个树枝节点、树叶节点只需要找到其父节点即可。
 *      缺点：
 *          ■ 不易控制树枝构件的类型；
 *          ■ 不易使用继承的方法来增加新的行为。
 *
 * 场景：
 *      ■ 需要描述对象的部分和整体的等级结构，如树形菜单、文件和文件夹管理。
 *      ■ 需要客户端忽略个体构件和组合构件的区别，平等对待所有的构件。
 *
 * @author king
 * @date 2021-06-08 13:42
 */
public class CompositePattern {
    public static void main(String[] args) {
        // 主节点
        ConcreteCompany root = new ConcreteCompany("张三", "CEO", 100000);
        ConcreteCompany developDep = new ConcreteCompany("李四", "研发部经理", 12000);
        ConcreteCompany salesDep = new ConcreteCompany("王五", "销售部经理", 15000);
        ConcreteCompany financeDep = new ConcreteCompany("马六", "财务部经理", 10000);

        // 子节点
        Employee e1 = new Employee("A", "研发部", 3000);
        Employee e2 = new Employee("B", "研发部", 2500);
        Employee e3 = new Employee("C", "研发部", 4000);
        Employee e4 = new Employee("D", "研发部", 6000);
        Employee e5 = new Employee("E", "销售部", 3500);
        Employee e6 = new Employee("F", "销售部", 2300);
        Employee e7 = new Employee("G", "销售部", 5000);
        Employee e8 = new Employee("H", "财务部", 3800);
        Employee e9 = new Employee("I", "财务部", 4300);

        // 生成树
        root.add(developDep);
        root.add(salesDep);
        root.add(financeDep);
        developDep.add(e1);
        developDep.add(e2);
        developDep.add(e3);
        developDep.add(e4);
        salesDep.add(e5);
        salesDep.add(e6);
        salesDep.add(e7);
        financeDep.add(e8);
        financeDep.add(e9);

        // 显示层次
        System.out.println(root.getInfo());
        display(root);
    }

    /**
     * 递归遍历
     * @param root
     */
    private static void display(ConcreteCompany root) {
        for (Company company : root.getChild()) {
            if (company instanceof Employee){
                // 子节点
                System.out.println(company.getInfo());
            }else{
                // 父节点
                System.out.println("\n" + company.getInfo());
                display((ConcreteCompany)company);
            }
        }
    }
}
